package tp.pr5;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;

import org.apache.commons.cli.BasicParser;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;

import tp.pr5.cityLoader.CityLoaderFromTxtFile;
import tp.pr5.cityLoader.cityLoaderExceptions.WrongCityFormatException;
import tp.pr5.console.Console;
import tp.pr5.console.ConsoleController;
import tp.pr5.gui.GUIController;
import tp.pr5.gui.MainWindow;

/**
 * Main Class
 */
public class Main 
{
	/**
	 * Default constructor.
	 * 
	 * @param args
	 */

	public static void main(String[] args) 
	{
		
		CommandLineParser commandLineParser = null;
		CommandLine commandLine = null;
		
		Options params = new Options();

		//Creates the option map
		Option maps = new Option("m", "map", true, "File with the description of the city");
		maps.setArgName("mapfile");
		//Creates the interface option
		Option interfaces = new Option("i", "interface", true, "The type of interface: console, swing or both");
		interfaces.setArgName("type");
		//Adds all the options to the class "params" created
		params.addOption(maps);
		params.addOption(interfaces);
		params.addOption("h", "help", false, "Shows this help message");
		
		try
		{
			String interfaceWindow;
			String map = null;
			
			commandLineParser = new BasicParser();
			commandLine = commandLineParser.parse(params, args);
			interfaceWindow = "console";
			/*Checks if the user types the help menu. It will show a header plus the main class and the commands needed to execute it
			otherwise it will check the rest of the commands*/
			if(commandLine.hasOption("h"))
			{
				System.out.println("Execute this assignment with these parameters:");
				new HelpFormatter().printHelp(Main.class.getCanonicalName() + " [-h] [-i <type>] [-m <mapfile>]", params);
			}
			else
			{
				//Checks if the option "m" has a text referring to the map otherwise it will show an error and exit
				if(commandLine.hasOption("m"))
				{
					map = commandLine.getOptionValue("m");
				}
				else
				{
					System.err.println("Map file not specified");
					System.exit(1);
				}
				/*Checks if the option "i" has the text console or swing so it can be executed in any of those 2 models
				otherwise it will throw an error and exit the system*/
				if(commandLine.hasOption("i"))
				{
					interfaceWindow = commandLine.getOptionValue("i");
					if(!interfaceWindow.equalsIgnoreCase("console") && !interfaceWindow.equalsIgnoreCase("swing") && !interfaceWindow.equalsIgnoreCase("both"))
					{
						System.err.println("Wrong type of interface");
						System.exit(3);
					}
				}
				else
				{
					System.err.println("Interface not specified");
					System.exit(1);
				}
				
				RobotEngine robotEngine;
				
				String name = map;
				CityLoaderFromTxtFile file = new CityLoaderFromTxtFile();
				File archivo = new File(name);
				InputStream in = null;
				
				//If the file does not exists it will throw an exception with an error message
				try {
					
					in = new FileInputStream(archivo);
				} catch (FileNotFoundException e) {
					
					System.err.println("Error reading the map file: " + map + 
								 	   " (No existe el fichero o el directorio)");
					System.exit(2);
				}

				//Now the file name is correct but if the format is incorrect it will throw an exception with an error message
				try {
					
					robotEngine = new RobotEngine(file.loadCity(in), file.getInitialPlace(), Direction.NORTH);
					
					//Checks if the simulation has to be run with interface, console or both
					if(interfaceWindow.equalsIgnoreCase("swing"))
					{
						GUIController guiController = new GUIController(robotEngine);
						MainWindow mainWindow = new MainWindow(guiController);
						guiController.startController();
						
					}
					else if(interfaceWindow.equalsIgnoreCase("console"))
					{
						Console console = new Console();
						ConsoleController cc = new ConsoleController(robotEngine);
					
						cc.registerEngineObserver(console);
						cc.registerItemContainerObserver(console);
						cc.registerRobotObserver(console);
						
						cc.startController();
					}
					//Starts the simulation with both interfaces. Can't execute commands in console
					else
					{
						GUIController guiController = new GUIController(robotEngine);
						MainWindow mainWindow = new MainWindow(guiController);
						Console console = new Console();
						ConsoleController cc = new ConsoleController(robotEngine);
						
						cc.registerEngineObserver(console);
						cc.registerItemContainerObserver(console);
						cc.registerRobotObserver(console);
						
						guiController.startController();
					}
					
				}catch (WrongCityFormatException e) {
					System.err.println("Error the map is incorrect");
					System.exit(2);
				} catch (IOException e) {
					e.printStackTrace();
				}
			}

		} catch(Exception e){
			System.err.print("Map file not specified");
			System.exit(1);
		}
	}
}